import sys
from pathlib import Path
from typing import List

from pydantic_settings import BaseSettings


class Settings(BaseSettings):
    class Config:
        # .env环境变量文件中定义的变量会覆盖Settings类中定义的变量名,忽略大小写
        # 多个环境变量文件，按顺序读取,后面会覆盖前面,没找到就不加载不报错
        # .env文件中变量 要与Settings类的变量名匹配, 可少不能多
        env_file = (".env", ".env.dev", ".env.prod")

        # env_file = ".env.prod" if os.getenv("PROJECT_ENV") == "prod" else ".env.dev"

    # 环境配置: dev prod
    # project_env: str = "dev"
    # debug: bool = True if project_env != "dev" else False
    # debug模式
    debug: bool = False

    # 项目标题
    project_title: str = "FastAPI 后端"
    # 项目描述
    project_description: str = "一个牛逼的API后端"
    # 项目版本
    project_version: str = "0.0.1"

    # url的前缀
    url_prefix: str = "/api/v1"
    # host
    server_host: str = "localhost"
    server_port: int = 8000

    # 是否启用 /test 接口
    enable_test_router: bool = True

    #  swagger docs 的登陆重定向地址
    swagger_ui_oauth2_redirect_url: str = "/docs/oauth2-redirect"
    # swagger docs 额外配置
    swagger_ui_parameters: dict = {"docExpansion": None}
    # /docs 获取 token 的 url
    oauth2_token_url: str = url_prefix + "/test/auth/token"

    # 项目根目录
    base_dir: Path = Path(__file__).absolute().parent.parent
    # 日志目录
    log_dir: Path = base_dir / "logs"
    # 静态资源
    static_dir: Path = base_dir / "static"
    static_url_prefix: str = "/static"
    # 用户上传目录
    media_dir: Path = base_dir / "media"
    media_url_prefix: str = "/media"
    # jinja2 模板目录
    jinja2_templates_dir: Path = base_dir / "backend" / "templates"

    # 中间件配置
    # 跨域请求
    cors_origins: List[str] = ["*"]
    cors_allow_credentials: bool = True
    cors_allow_methods: List[str] = ["PUT", "POST", "GET", "DELETE", "OPTIONS"]
    cors_allow_headers: List[str] = ["*"]
    # Session
    session_secret_key: str = "sadehewagbwft34ba"
    session_cookie: str = "session_id"
    session_max_age: int = 14 * 24 * 60 * 60
    # SetSessionMiddleware
    session_cookie_name: str = "session"
    # TrustedHostMiddleware
    allowed_hosts: List[str] = ["*"]

    # 日志中间件的白名单，只填写去除 url_prefix 的部分
    logger_path_white_list: List[str] = [
        "/user/captcha",
        "/test/files",
        "/test/uploadfile",
    ]

    # 数据库
    mysql_host: str = "localhost"
    mysql_port: int = 3306
    mysql_user: str = "root"
    mysql_password: str = "root_password"
    mysql_database: str = "db_demo"

    # redis
    cache_redis_url: str = "redis://localhost:6379/0"

    # captcha
    # 图片验证码有效时间
    captcha_seconds: int = 60 * 60
    # 图片验证码key
    captcha_key: str = "captcha:{}"

    # jwt加密的盐
    jwt_secret_key: str = "lbrvwAwLCyyjkQKH"
    # jwt加密算法
    jwt_algorithm: str = "HS256"
    # token过期时间，单位：秒
    jwt_exp_seconds: int = 7 * 24 * 60 * 60

    @property
    def tortoise_orm_model_modules(self) -> List[str]:
        return ["aerich.models", "models"]

    @property
    def tortoise_orm_config(self) -> dict:
        return {
            "connections": {
                "default": {
                    "engine": "tortoise.backends.mysql",
                    "credentials": {
                        "host": self.mysql_host,
                        "port": self.mysql_port,
                        "user": self.mysql_user,
                        "password": self.mysql_password,
                        "database": self.mysql_database,
                    },
                },
                "default1": {
                    "engine": "tortoise.backends.sqlite",
                    "credentials": {"file_path": "test.db"},
                },
            },
            "apps": {
                "base": {
                    "models": self.tortoise_orm_model_modules,
                    "default_connection": "default",
                }
            },
            "use_tz": False,
            "timezone": "Asia/Shanghai",
        }

    @property
    def loguru_config(self):
        return {
            "handlers": [
                {
                    "sink": sys.stdout,
                    "level": "DEBUG",
                    "format": "<green>{time:YYYY-MM-DD HH:mm:ss.SSS}</green> | {thread.name} | "
                    "<level>{level}</level> | "
                    "<cyan>{module}</cyan>:<cyan>{function}</cyan>:<cyan>{line}</cyan> - "
                    "<level>{message}</level>",
                    "filter": lambda record: record["level"].name == "DEBUG",
                },
                {
                    "sink": self.log_dir / "info.log",
                    "level": "INFO",
                    "rotation": "10 MB",
                    "retention": "1 week",
                    "encoding": "utf-8",
                    "format": "{time:YYYY-MM-DD HH:mm:ss.SSS} | {thread.name} | {level} | "
                    "{module} : {function}:{line} -  {message}",
                    "filter": lambda record: record["level"].name == "INFO",
                },
                {
                    "sink": sys.stdout,
                    "level": "SUCCESS",
                    "format": "<level>{message}</level>",
                    "filter": lambda record: record["level"].name == "SUCCESS",
                },
                {
                    "sink": self.log_dir / "warning.log",
                    "level": "WARNING",
                    "rotation": "10 MB",
                    "retention": "1 week",
                    "encoding": "utf-8",
                    "format": "{time:YYYY-MM-DD HH:mm:ss.SSS} | {thread.name} | {level} | "
                    "{module} : {function}:{line} -  {message}",
                    "filter": lambda record: record["level"].name == "WARNING",
                },
                {
                    "sink": self.log_dir / "error.log",
                    "serialize": True,
                    "level": "ERROR",
                    "retention": "1 week",
                    "rotation": "10 MB",
                    "encoding": "utf-8",
                    "format": "{time:YYYY-MM-DD HH:mm:ss.SSS} | {thread.name} | {level} | "
                    "{module} : {function}:{line} -  {message}",
                    "filter": lambda record: record["level"].name == "ERROR",
                },
                {
                    "sink": self.log_dir / "critical.log",
                    "level": "CRITICAL",
                    "rotation": "10 MB",
                    "retention": "1 week",
                    "encoding": "utf-8",
                    "format": "{time:YYYY-MM-DD HH:mm:ss.SSS} | {thread.name} | {level} | "
                    "{module} : {function}:{line} -  {message}",
                    "filter": lambda record: record["level"].name == "CRITICAL",
                },
            ],
        }
